package ru.maxmatveev.dyndao;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.annotation.ElementType;

/**
 * Filter parameters container.
 * @author Max Matveev
 *         Date: Dec 20, 2008
 *         Time: 6:30:02 PM
 */
public class Restriction {
    
    /**
     * Resitriction comparison values.
     *
     * @author cthulhu
     * Created on Dec 28, 2008
     */
    public static enum Comparison {
        /** Strict EQUALS comparison. */
        EQUALS,
        /** Case-insensitive EQUALS comparison. */
        IEQUALS,
        /** Case-sensitive LIKE comparison. */
        LIKE,
        /** Case-insensitive LIKE comparison. */
        ILIKE
    }
    /**
     * Restirction logical operations.
     *
     * @author cthulhu
     * Created on Dec 28, 2008
     */
    public static enum LogicalOp {
        /** Logical AND. */
        AND,
        /** Logical OR. */
        OR,
        /** Logical NOT. */
        NOT
    }
    /** Field field  */
    private String field;
    /** Field value  */
    private Object value;
    /** Field child1  */
    private Restriction child1;
    /** Field child2  */
    private Restriction child2;
    /** Field comparison  */
    private Comparison comparison;
    /** Field logicalOp  */
    private LogicalOp logicalOp;

    /**
     * Get name of field used for filtering.
     * @return field name
     */
    public String getField() {
        return field;
    }

    /**
     * Get value used for filtering.
     * @return filtering value
     */
    public Object getValue() {
        return value;
    }

    /**
     * Get first restriction parameters used in logical restriction operations.
     * @return first Restriction parameter
     */
    public Restriction getChild1() {
        return child1;
    }

    /**
     * Get second restriction parameters used in logical restriction operations.
     * @return second parameter
     */
    public Restriction getChild2() {
        return child2;
    }

    /**
     * Get comparison operation.
     * @return comparison operation
     */
    public Comparison getComparison() {
        return comparison;
    }

    /**
     * Get logical operation.
     * @return logical operation
     */
    public LogicalOp getLogicalOp() {
        return logicalOp;
    }

    /**
     * Construct Restriction object with given field name, filtering value and comparison operation.
     * @param field field name
     * @param value value
     * @param comparison comparison operation
     */
    private Restriction(String field, Object value, Comparison comparison) {
        this.field = field;
        this.value = value;
        this.comparison = comparison;
    }

    /**
     * Construct Restriction object with given logical operation.
     * @param child1 first argument of logical operation
     * @param child2 second argument of logical operation (pass null if not used)
     * @param logicalOp logical operation
     */
    private Restriction(Restriction child1, Restriction child2, LogicalOp logicalOp) {
        this.child1 = child1;
        this.child2 = child2;
        this.logicalOp = logicalOp;
    }

    /**
     * Filter by "equals" comparison.
     * @param field field name
     * @param value filter value
     * @return consrtucted Restriction object
     */
    public static Restriction eq(String field, Object value) {
        return new Restriction(field, value, Comparison.EQUALS);
    }

    /**
     * Filter by "case-insensitive equals" comparison.
     * @param field field name
     * @param value filtering value
     * @return consrtucted Restriction object
     */
    public static Restriction ieq(String field, String value) {
        return new Restriction(field, value, Comparison.IEQUALS);
    }

    /**
     * Filter by "case-sensitive like" comparison.
     * @param field field name
     * @param value filter value
     * @return consrtucted Restriction object
     */
    public static Restriction like(String field, Object value) {
        return new Restriction(field, value, Comparison.LIKE);
    }

    /**
     * Filter by "case-insensitive like" comparison.
     * @param field field name
     * @param value filter value
     * @return consrtucted Restriction object
     */
    public static Restriction ilike(String field, Object value) {
        return new Restriction(field, value, Comparison.ILIKE);
    }

    /**
     * Logical AND operation on provided restrictions.
     * @param value1 argument 1
     * @param value2 argument 2
     * @return consrtucted Restriction object
     */
    public static Restriction and(Restriction value1, Restriction value2) {
        return new Restriction(value1, value2, LogicalOp.AND);
    }

    /**
     * Logical OR operation on provided restrictions.
     * @param value1 argument 1
     * @param value2 argument 2
     * @return consrtucted Restriction object
     */
    public static Restriction or(Restriction value1, Restriction value2) {
        return new Restriction(value1, value2, LogicalOp.OR);
    }

    /**
     * Logical NOT operation on provided restriction.
     * @param value1 argument 1
     * @return consrtucted Restriction object
     */
    public static Restriction not(Restriction value1) {
        return new Restriction(value1, null, LogicalOp.NOT);
    }

    /**
     * Marks Restirction type parameter to be used in restriction of selecting parent entity(ies)
     * containing Collection of this entities.
     *
     * @author cthulhu
     * Created on Dec 29, 2008
     */
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.PARAMETER)
    public @interface Parent {
        /** @return Parent entity class */
        Class parentClass();
        /** @return Field name in parent entity representing Collection of this entities */
        String fieldName();
    }

    /**
     * Marks field to be used in restriction of selecting parent entity(ies)
     * containing Collection of this entities by specific field.
     *
     * @author cthulhu
     * Created on Dec 29, 2008
     */
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.PARAMETER)
    public @interface ParentField {
        /** @return Parent entity class */
        Class parentClass();
        /** @return Field name in parent entity representing Collection of this entities */
        String fieldName();
        /** @return Name of field in Parent entity to use filter on */
        String filterFieldName();
        /** @return Comparison opertaion for this field */
        Comparison filterFieldComparison();
    }

    /**
     * Marks field to be used in restriction of selecting parent entity(ies)
     * containing Collection of this entities by parent ID.
     *
     * @author cthulhu
     * Created on Dec 29, 2008
     */
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.PARAMETER)
    public @interface ParentId {
        /** @return Parent entity class */
        Class parentClass();
        /** @return Field name in parent entity representing Collection of this entities */
        String fieldName();
    }

    /**
     * Restirct entity(ies) by specific field value.
     *
     * @author cthulhu
     * Created on Dec 29, 2008
     */
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.PARAMETER)
    public @interface Field {
        /** @return name of field in entity to use restriction on */
        String fieldName();
        /** @return Comparison opertation */
        Comparison comparison();
    }

    /**
     * Restrict entity(ies) by Restriction criteria.
     *
     * @author cthulhu
     * Created on Dec 29, 2008
     */
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.PARAMETER)
    public @interface Restrict {
    }

}
